using System;
using System.Drawing;

using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;

namespace iDorm
{
	// class Object
	//
	// Base class for any item that can be placed in the room
	public class Object : IComparable
	{
		private string name;
		private float x, y, z;

		private float length, width, height;

		private float angle;

		public bool moving = false;
		public bool selected = false;
		private bool rotated = false;

		// 3D representation of object
		Model model;

		Matrix world;

		// Object Constructor
		// Description: Creates an object based on certain criteria
		// Input: name, Location, length, width, height
		// Output: Object on screen
		public Object(string name, float x, float y, float z, float length, float width, float height)
		{
			this.name = name;

			this.x = x;
			this.y = y;
			this.z = z;

			this.length = length;
			this.width = width;
			this.height = height;

			angle = 0.0f;

			this.Move(x,y,z, -1, -1);
		}
		// Attaches model
		public void AttachModel(Model m)
		{
			model = m;
		}
		// Returns model
		public Model GetModel()
		{
			return model;
		}
		//Moves object to new width / length / location
		public void Move(float x, float y, float z, float roomWidth, float roomLength)
		{
			float length, width;
			if (rotated)
			{
				length = this.width;
				width = this.length;
			}
			else
			{
				length = this.length;
				width = this.width;
			}


			if (roomLength > 0 && roomWidth > 0)
			{
				if ((x - length / 2) < (-roomLength / 2))
					x = -roomLength / 2 + length / 2;
				if ((x + length / 2) > (roomLength / 2))
					x = roomLength / 2 - length / 2;
				if ((z - width / 2) < (-roomWidth / 2))
					z = -roomWidth / 2 + width / 2;
				if ((z + width / 2) > (roomWidth / 2))
					z = roomWidth / 2 - width / 2;
			}
			this.x = x;
			this.y = y;
			this.z = z;

			world = Matrix.Scaling(this.length, this.height, this.width) * Matrix.RotationY(angle) * Matrix.Translation(x, y, z);
			
			return;
		}
		// If object is selected, color changes
		// Renders screen
		public void Render()
		{
			if (selected)
			{
				model.SelectColor(Color.Red, false);
			}
			else
			{
				model.SelectColor(Color.White, true);
			}
			model.Render(world);
		}

		// Rotates object clockwise by changing its properties
		public void RotateCW(float angle)
		{
			rotated = !rotated;

			this.angle -= angle;

			if (angle < - (float)Math.PI / 2)
				angle = (float) Math.PI / 2;

			world = Matrix.Scaling(length, height, width) * Matrix.RotationY(this.angle) * Matrix.Translation(x, y, z);
		}
		// Rotates object Counter clockwise by changing its properties
		public void RotateCCW(float angle)
		{
			rotated = !rotated;
			this.angle += angle;

			if (angle > (float)Math.PI / 2)
				angle = - (float) Math.PI / 2;

			world = Matrix.Scaling(length, height, width) * Matrix.RotationY(this.angle) * Matrix.Translation(x, y, z);
		}
		// The following functions are getters which return individual properties of the objects
		public float GetX()
		{
			return x;
		}
		public void setAngle(float angle)
		{
			this.angle = angle;
			world = Matrix.Scaling(length, height, width) * Matrix.RotationY(this.angle) * Matrix.Translation(x, y, z);

			if (angle == 0.0f || angle == (float) Math.PI)
				rotated = false;
			else
				rotated = true;
		}

		public float GetY()
		{
			return y;
		}
		
		public float GetZ()
		{
			return z;
		}

		public string GetName()
		{
			return name;
		}

		public float GetLength()
		{
			return length;
		}

		public float GetWidth()
		{
			return width;
		}
		
		public float GetHeight()
		{
			return height;
		}
		public float GetAngle()
		{
			return angle;
		}
		// Returns true if object and mouse coordinates intersect
		public bool Intersects(Point p)
		{
			int x1 = (int) ((this.x - this.length / 2) * 40);
			int x2 = (int) ((this.x + this.length / 2) * 40);
			int z1 = (int) ((this.z - this.width / 2) * 40);
			int z2 = (int) ((this.z + this.width / 2) * 40);

			if ((p.X > x1 && p.X < x2) && (p.Y > z1 && p.Y < z2))
			{
				return true;
			}
			return false;
		}

		public bool Intersects(Object o)
		{
			float left1 = o.GetX() - o.GetLength() / 2.0f;
			float right1 = o.GetX() + o.GetLength() / 2.0f;
			float top1 = o.GetZ() + o.GetWidth() / 2.0f;
			float bottom1 = o.GetZ() - o.GetWidth() / 2.0f;

			float left2 = this.GetX() - this.GetLength() / 2.0f;
			float right2 = this.GetX() + this.GetLength() / 2.0f;
			float top2 = this.GetZ() + this.GetWidth() / 2.0f;
			float bottom2 = this.GetZ() - this.GetWidth() / 2.0f;


			if (right2 > left1 && left2 < right1 && top2 > bottom1 && bottom2 < top1) 
			{
				return true;
			}
			else
			{
				return false;
			}
		}



		// Checks if object is within boundaries of room
		private bool CheckBounds(float x, float y, float z, float roomLength, float roomWidth)
		{
			if (roomLength < 0 && roomWidth < 0)
				return true;

			if ((x - length / 2) > (-roomLength / 2) && 
				(x + length / 2)< (roomLength / 2) &&
				(z - width / 2) > (-roomWidth / 2) &&
				(z + width / 2) < (roomWidth / 2))
				return true;
			else
				return false;
		}

		public int CompareTo(object a)
		{
			if (a is Object)
			{
				Object obj = (Object)a;
				return this.y.CompareTo(obj.y);
			}
			else
				throw new ArgumentException("object a is not type Object");
		}
	}
}
